package com.bootdo.system.controller;

import com.alibaba.fastjson.JSONObject;
import com.bootdo.common.controller.BaseController;
import com.smart.common.utils.DateUtils;
import com.smart.common.utils.HttpCallUtil;
import com.smart.common.utils.R;
import com.smart.common.utils.StringUtils;
import com.smart.common.utils.redis.RedisManager;
import com.smart.constants.EurekaAdminConfig;
import com.smart.constants.EurekaServerStatus;
import com.smart.constants.RedisIndex;
import com.smart.enums.RedisKeyEnum;
import org.apache.http.HttpStatus;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.*;
//FIXME 待测试集群环境下的操作
@RequestMapping("/sys/regserver")
@Controller
public class EurekaServerController extends BaseController {
	private String prefix="system/regserver"  ;
	@Autowired
	RedisManager redisManager;
	@Autowired
	EurekaAdminConfig eurekaAdminConfig;

	/**
	 * 转向服务列表页面
	 */
	@GetMapping("")
	String user(Model model) {
		return prefix + "/regserver";
	}

	/**
	 * 查询当前服务列表
	 */
	@GetMapping("/list")
	@ResponseBody
	List<Map<String,String>> list() {
		//服务列表key
		String regServerSetKey = RedisKeyEnum.EUREKA_SERVER_SET.getCode();
		//服务实例key前缀
		String regServerInstanceKey = RedisKeyEnum.EUREKA_SERVER_INSTANCE.getCode();

		//1.查询服务列表
		Set<String> smembers = redisManager.smembers(regServerSetKey, RedisIndex.INDEX_12);
		//保存所有服务实例数据
		List<Map<String,String>> list = new ArrayList<Map<String,String>>();
		//2.遍历服务列表,查询每个服务的实例,保存到list
		for(String appName:smembers){
			//2.1 拼装服务实例key
			String instanceHashKey = regServerInstanceKey + ":" + appName;
			//2.2查询服务实例
			Map<String, String> instanceMap = redisManager.getHashAll(instanceHashKey, RedisIndex.INDEX_12);
			//2.3遍历服务实例,保存到list
			for(Map.Entry<String,String> entry : instanceMap.entrySet()){
				String key = entry.getKey();//服务instanceId
				String value = entry.getValue();//服务信息
				JSONObject jsonObject = JSONObject.parseObject(value);
				Map<String,String> map = new HashMap<String,String>();
				map.put("instanceId",jsonObject.getString("instanceId"));
				map.put("appName",jsonObject.getString("appName"));
				map.put("refreshTime",jsonObject.getString("refreshTime"));
				map.put("status",jsonObject.getString("status"));
				list.add(map);
			}

		}
		return list;
	}

	/**
	 * 上线服务
	 */
	@PostMapping("/doOffline")
	@ResponseBody
	R doOffline(String instanceId,String appName) {
		if(StringUtils.isEmpty(instanceId)){
			return R.error("instanceId can not be null");
		}
		if(StringUtils.isEmpty(appName)){
			return R.error("appName can not be null");
		}
		//1.校验不能将所有当前服务全部下线,至少要留一个继续运行
		//1.1查询所有当前服务实例
		String regServerInstanceKey = RedisKeyEnum.EUREKA_SERVER_INSTANCE.getCode();
		String instanceHashKey = regServerInstanceKey + ":" + appName;
		Map<String, String> instanceMap = redisManager.getHashAll(instanceHashKey, RedisIndex.INDEX_12);
		//1.2遍历服务实例map,统计所有状态,如果上线状态数量>2,则允许本次下线
		//TODO  未考虑并发操作情况,先通过人工控制,V3.0添加分布式锁处理,
		int onlineNum = 0;
		for(Map.Entry<String,String> entry : instanceMap.entrySet()){
			String key = entry.getKey();//服务instanceId
			String value = entry.getValue();//服务信息
			JSONObject jsonObject = JSONObject.parseObject(value);
			String status = jsonObject.getString("status");
			if(EurekaServerStatus.ON_LINE.equals(status)){
				onlineNum ++;
			}
		}
		if(onlineNum >eurekaAdminConfig.getLeastOnLineNum()){
			String putUrl = eurekaAdminConfig.getEurekaZone()+"/apps/"+appName+"/"+instanceId+"/status?value=OUT_OF_SERVICE";
			JSONObject jsonObject = HttpCallUtil.httpPut(putUrl);
			if(HttpStatus.SC_OK == jsonObject.getInteger("code")){
				//下线成功,更新记录状态
				JSONObject object = new JSONObject();
				object.put("instanceId",instanceId);
				object.put("appName",appName);
				object.put("refreshTime", DateUtils.getNowDateTimeStr());
				object.put("status", EurekaServerStatus.OFF_LINE);
				redisManager.setHashString(instanceHashKey,instanceId,object.toJSONString(), RedisIndex.INDEX_12);

				return R.ok();
			}else{
				return R.error(jsonObject.getInteger("code"),jsonObject.getString("msg"));
			}
		}else{
			return R.error("当前在线服务数量只剩1个,不允许下线操作");
		}
	}

	/**
	 * 下线服务
	 */
	@PostMapping("/doOnline")
	@ResponseBody
	R doOnline(String instanceId,String appName) {
		if(StringUtils.isEmpty(instanceId)){
			return R.error("instanceId can not be null");
		}
		if(StringUtils.isEmpty(appName)){
			return R.error("appName can not be null");
		}
		String putUrl = eurekaAdminConfig.getEurekaZone()+"/apps/"+appName+"/"+instanceId+"/status?value=UP";
		JSONObject jsonObject = HttpCallUtil.httpPut(putUrl);
		if(HttpStatus.SC_OK == jsonObject.getInteger("code")){
			//上线成功,更新状态
			JSONObject object = new JSONObject();
			object.put("instanceId",instanceId);
			object.put("appName",appName);
			object.put("refreshTime", DateUtils.getNowDateTimeStr());
			object.put("status", EurekaServerStatus.ON_LINE);
			String regServerInstanceKey = RedisKeyEnum.EUREKA_SERVER_INSTANCE.getCode();
			String instanceHashKey = regServerInstanceKey + ":" + appName;
			redisManager.setHashString(instanceHashKey,instanceId,object.toJSONString(), RedisIndex.INDEX_12);

			return R.ok();
		}else{
			return R.error(jsonObject.getInteger("code"),jsonObject.getString("msg"));
		}
	}

	/**
	 * 剔除服务,注意剔除的服务在下次心跳时会重新注册
	 */
	@PostMapping("/doRemove")
	@ResponseBody
	R doRemove(String instanceId,String appName) {
		if(StringUtils.isEmpty(instanceId)){
			return R.error("instanceId can not be null");
		}
		if(StringUtils.isEmpty(appName)){
			return R.error("appName can not be null");
		}
		String putUrl = eurekaAdminConfig.getEurekaZone()+"/apps/"+appName+"/"+instanceId+"/status?value=DOWN";
		JSONObject jsonObject = HttpCallUtil.httpPut(putUrl);
		String regServerInstanceKey = RedisKeyEnum.EUREKA_SERVER_INSTANCE.getCode();
		String instanceHashKey = regServerInstanceKey + ":" + appName;
		redisManager.delHash(instanceHashKey,instanceId,RedisIndex.INDEX_12);

		if(HttpStatus.SC_OK == jsonObject.getInteger("code")){
			return R.ok();
		}else{
			return R.error(jsonObject.getInteger("code"),jsonObject.getString("msg"));
		}
	}


}
